#include "genFromDisk.h"

namespace sp::Image::Gen{

void registe_genFromDisk(){
    genFromDisk::registe();
}

genFromDisk::genFromDisk(std::vector<std::string> v){ // std::string path, long total_cnt, int fps, int width, int height
    assert(v.size() == 5);
    name = "genFromDisk";
    class_name = "Image-Gen-genFromDisk";
    Separate_Function = true;
    path = v[0];
    total_cnt = std::stol(v[1]);
    fps = std::stoi(v[2]);
    width = std::stoi(v[3]);
    height = std::stoi(v[4]);
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({},MAT));
}

genFromDisk::genFromDisk(std::string path, char* video_ptr_head, long total_cnt, int fps, int width, int height){
    name = "genFromDisk";
    class_name = "Image-Gen-genFromDisk";
    Separate_Function = true;
    this->path = path;
    this->video_ptr_head = video_ptr_head;
    this->total_cnt = total_cnt;
    this->fps = fps;
    this->width = width;
    this->height = height;
    current_video_ptr = video_ptr_head;
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({},MAT));
}

genFromDisk::genFromDisk(){
    name = "genFromDisk";
    class_name = "Image-Gen-genFromDisk";
    Separate_Function = true;
    current_video_ptr = video_ptr_head;
    cnt = 0;
    data_type_support.push_back(std::pair<std::vector<uint8_t>, uint8_t>({},MAT));
}

genFromDisk::~genFromDisk(){

}

void genFromDisk::registe(){
    Function::Register("Image-Gen-genFromDisk", createObject);
    Function::Register("Image-Gen-genFromDisk", createObject2);
}

Function* genFromDisk::createObject(std::vector<std::string> params){
    return new genFromDisk(params);
}

Function* genFromDisk::createObject2(){
    return new genFromDisk();
}

void genFromDisk::start(){
    capture.open(this->path);
    if(!capture.isOpened()){
        std::cout << "video open failed!" << std::endl;
    }
    gettimeofday(&time_start, NULL);
}

bool genFromDisk::waitForResource(){
    return true;
}

void genFromDisk::process(std::vector<std::vector<Data*>>& data_input, std::vector<Data*>& data_output){
    // 验证输入个数
    assert(data_input.size() != 0);
    assert(data_input[0].size() == 1);
    // 生成图片
    for(int i = 0; i < batch_size; i++){
        char* mat_data_ptr = executor->malloc(height, width);
        cv::Mat* frame = new cv::Mat(height, width, CV_8UC3);
        frame->data = (uchar*)mat_data_ptr;
        frame->datastart = frame->data;
        frame->dataend = frame->datastart + height*width*3;
        frame->datalimit = frame->dataend;
        capture >> *frame;
        if(frame->empty()){
            data_output.push_back(DATA_END);
            break;
        }else{
            data_input[i][0]->set(frame->channels(), frame->rows, frame->cols, (uchar*)mat_data_ptr);
            data_output.push_back(data_input[i][0]);
        }
    }
    struct timeval t;
    gettimeofday(&t, NULL);
    double time_cost = (t.tv_sec + ((double)t.tv_usec/1000000)) - (time_start.tv_sec + ((double)time_start.tv_usec/1000000));
    while(time_cost < ((double)1.0/fps)*cnt){
        gettimeofday(&t, NULL);
        time_cost = (t.tv_sec + ((double)t.tv_usec/1000000)) - (time_start.tv_sec + ((double)time_start.tv_usec/1000000));
    }
    cnt++;
}

bool genFromDisk::releaseResource(){
    return true;
}

void genFromDisk::finish(){
    capture.release();
}

bool genFromDisk::process(){
    cv::Mat frame;
    capture >> frame;
    if(cnt >= total_cnt){
        return false;
    }else{
        if(frame.empty()){
            std::cout << "video length is not enough." << std::endl;
            assert(false);
        }
        memcpy(current_video_ptr, frame.datastart, frame.dataend - frame.datastart);
        current_video_ptr += frame.dataend - frame.datastart;
        std::cout << "load video: " << cnt++ << std::endl;
        return true;
    }
}

void genFromDisk::copy(Function* other){
    Function::defaultCopy(other);
    genFromDisk* oth = dynamic_cast<genFromDisk*>(other);
    this->path = oth->path;
    this->video_ptr_head = oth->video_ptr_head;
    this->total_cnt = oth->total_cnt;
    this->fps = oth->fps;
    this->width = oth->width;
    this->height = oth->height;
}

};